/*
 * Copyright (c) 2018.
 * http://www.ulabcare.com
 */

package com.mt.roll.upms.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.mt.roll.core.api.Assert;
import com.mt.roll.core.base.BaseService;
import com.mt.roll.core.dal.entity.Resource;
import com.mt.roll.core.dal.entity.SysMenu;
import com.mt.roll.core.dal.entity.SysMenuResource;
import com.mt.roll.core.dal.service.ResourceServiceBiz;
import com.mt.roll.core.dal.service.SysMenuResourceServiceBiz;
import com.mt.roll.core.dal.service.SysMenuServiceBiz;
import com.mt.roll.core.enums.ResourceCategoryEnum;
import com.mt.roll.core.enums.SubsystemEnum;
import com.mt.roll.core.enums.WhetherEnum;
import com.mt.roll.core.params.IdListParam;
import com.mt.roll.core.params.IdParam;
import com.mt.roll.core.vo.*;
import com.mt.roll.upms.params.MenuResourceParam;
import com.mt.roll.upms.params.MenuResourceQueryParam;
import com.mt.roll.upms.service.MenuResourceService;
import com.mt.roll.upms.vo.ResourceVo;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 菜单资源服务接口实现类
 *
 * @author jiff
 * @date 2018-11-28
 * @since 1.0
 */
@Service
@Transactional
public class MenuResourceServiceImpl extends BaseService implements MenuResourceService {
    @Autowired
    private SysMenuResourceServiceBiz sysMenuResourceServiceBiz;
    @Autowired
    private SysMenuServiceBiz sysMenuServiceBiz;
    @Autowired
    private ResourceServiceBiz resourceServiceBiz;

    /**
     * 新增菜单资源
     *
     * @param menuResourceParam 菜单资源参数
     * @return 主键
     */
    @Override
    public R<IdListVo> add(MenuResourceParam menuResourceParam) {
        Long menuId = menuResourceParam.getMenuId();
        List<Long> resourceIds = menuResourceParam.getResourceIds();
        SysMenu menu = sysMenuServiceBiz.getById(menuId);
        Assert.notNull("菜单不存在", menu);
        Collection<Resource> resources = resourceServiceBiz.listByIds(resourceIds);
        if (resourceIds.size() != resources.size()) {
            return failed("资源不存在");
        }
        for (Resource resource : resources) {
            Assert.fail(resource.getCategory() > 0 && !menu.getCategory().equals(resource.getCategory()), "菜单分类和资源分类不一致");
        }
        //先过滤已有的菜单资源关系，再保存新增的菜单资源关系
        List<SysMenuResource> menuResources = sysMenuResourceServiceBiz.list(new QueryWrapper<SysMenuResource>().eq(SysMenuResource.MENU_ID, menuId));
        Map<Long, SysMenuResource> menuResourceMap = menuResources.stream().collect(Collectors.toMap(SysMenuResource::getResourceId, menuResource -> menuResource, (k1, k2) -> k1));
        resourceIds = resourceIds.stream().filter(id -> !menuResourceMap.containsKey(id)).collect(Collectors.toList());
        List<SysMenuResource> addMenuResources = resourceIds.stream()
                .map(resourceId -> setCommonField(new SysMenuResource().setMenuId(menuId).setResourceId(resourceId)))
                .collect(Collectors.toList());
        sysMenuResourceServiceBiz.saveBatch(addMenuResources);
        return successful(IdListVo.builder().ids(addMenuResources.stream().map(SysMenuResource::getId).collect(Collectors.toList())).build());
    }

    /**
     * 删除菜单资源
     *
     * @param idParam 主键参数
     * @return 主键
     */
    @Override
    public R<IdVo> delete(IdParam idParam) {
        sysMenuResourceServiceBiz.removeById(idParam.getId());
        return successful(IdVo.builder().id(idParam.getId()).build());
    }

    /**
     * 批量删除菜单资源
     *
     * @param idListParam 主键列表参数
     * @return 主键列表
     */
    @Override
    public R<IdListVo> delete(IdListParam idListParam) {
        sysMenuResourceServiceBiz.removeByIds(idListParam.getIds());
        return successful(IdListVo.builder().ids(idListParam.getIds()).build());
    }

    /**
     * 获取菜单资源列表，返回菜单关联的资源列表
     *
     * @param idParam 主键参数
     * @return 菜单资源列表
     */
    @Override
    public R<List<MenuResourceVo>> listByMenu(IdParam idParam) {
        //先查询菜单资源关系，再转换成Map<resourceId,SysMenuResource>，便于把资源列表转换成菜单资源列表
        List<SysMenuResource> menuResources = sysMenuResourceServiceBiz.list(new QueryWrapper<SysMenuResource>().eq(SysMenuResource.MENU_ID, idParam.getId()));
        if (CollectionUtils.isEmpty(menuResources)) {
            return successful(null);
        }
        Map<Long, SysMenuResource> menuResourceMap = menuResources.stream().collect(Collectors.toMap(SysMenuResource::getResourceId, menuResource -> menuResource, (k1, k2) -> k1));
        Collection<Resource> resources = resourceServiceBiz.listByIds(menuResources.stream().map(SysMenuResource::getResourceId).collect(Collectors.toList()));
        List<MenuResourceVo> menuResourceVos = resources.stream().map(resource -> {
            MenuResourceVo menuResourceVo = MenuResourceVo.builder().build();
            BeanUtils.copyProperties(resource, menuResourceVo);
            SysMenuResource menuResource = menuResourceMap.get(resource.getId());
            BeanUtils.copyProperties(menuResource, menuResourceVo);
            return menuResourceVo;
        }).collect(Collectors.toList());
        return successful(menuResourceVos);
    }

    /**
     * 获取资源列表，需要根据菜单分类返回未关联的资源列表
     *
     * @param menuResourceQueryParam 查询参数
     * @return 资源列表
     */
    @Override
    public R<List<ResourceVo>> listWithMenu(MenuResourceQueryParam menuResourceQueryParam) {
        SysMenu menu = sysMenuServiceBiz.getById(menuResourceQueryParam.getMenuId());
        Assert.notNull("菜单不存在", menu);
        List<SysMenuResource> menuResources = sysMenuResourceServiceBiz.list(new QueryWrapper<SysMenuResource>().eq(SysMenuResource.MENU_ID, menu.getId()));
        Map<Long, SysMenuResource> menuResourceMap = menuResources.stream().collect(Collectors.toMap(SysMenuResource::getResourceId, menuResource -> menuResource, (k1, k2) -> k1));
        List<Resource> allResources = resourceServiceBiz
                .list(new QueryWrapper<Resource>()
                        .eq(Resource.ENABLED, WhetherEnum.YES.getValue())
                        .and(wrapper -> wrapper.eq(Resource.SUBSYSTEM, SubsystemEnum.COMMON.getValue())
                                .or().eq(Resource.SUBSYSTEM, SubsystemEnum.PLATFORM.getValue()))
                        .and(wrapper -> wrapper.eq(Resource.CATEGORY, ResourceCategoryEnum.COMMON.getValue())
                                .or().eq(Resource.CATEGORY, menu.getCategory()))
                        .like(StringUtils.isNotBlank(menuResourceQueryParam.getName()), Resource.NAME, menuResourceQueryParam.getName())
                        .like(StringUtils.isNotBlank(menuResourceQueryParam.getUrl()), Resource.URL, menuResourceQueryParam.getUrl()));
        List<Resource> resources = allResources.stream().filter(resource -> !menuResourceMap.containsKey(resource.getId())).collect(Collectors.toList());
        List<ResourceVo> resourceVos = com.mt.roll.core.utils.BeanUtils.copyList(resources, ResourceVo.class);
        return successful(resourceVos);
    }

    /**
     * 获取资源分页列表，需要根据菜单分类返回未关联的资源列表
     *
     * @param menuResourceQueryParam 查询参数
     * @return 资源分页列表
     */
    @Override
    public R<PageVo<ResourceVo>> pageWithMenu(MenuResourceQueryParam menuResourceQueryParam) {
        SysMenu menu = sysMenuServiceBiz.getById(menuResourceQueryParam.getMenuId());
        Assert.notNull("菜单不存在", menu);
        List<SysMenuResource> menuResources = sysMenuResourceServiceBiz.list(new QueryWrapper<SysMenuResource>().eq(SysMenuResource.MENU_ID, menu.getId()));
        IPage<Resource> page = resourceServiceBiz
                .page(new Page<>(menuResourceQueryParam.getCurrent(), menuResourceQueryParam.getSize()), new QueryWrapper<Resource>()
                        .eq(Resource.ENABLED, WhetherEnum.YES.getValue())
                        .and(wrapper -> wrapper.eq(Resource.SUBSYSTEM, SubsystemEnum.COMMON.getValue())
                                .or().eq(Resource.SUBSYSTEM, SubsystemEnum.PLATFORM.getValue()))
                        .and(wrapper -> wrapper.eq(Resource.CATEGORY, ResourceCategoryEnum.COMMON.getValue())
                                .or().eq(Resource.CATEGORY, menu.getCategory()))
                        .notIn(!CollectionUtils.isEmpty(menuResources), Resource.ID, menuResources.stream().map(SysMenuResource::getResourceId).collect(Collectors.toList()))
                        .like(StringUtils.isNotBlank(menuResourceQueryParam.getName()), Resource.NAME, menuResourceQueryParam.getName())
                        .like(StringUtils.isNotBlank(menuResourceQueryParam.getUrl()), Resource.URL, menuResourceQueryParam.getUrl()));
        return successful(new PageVo<>(page, ResourceVo.class));
    }

}
